﻿using System.ComponentModel;
using System.Diagnostics;
using System.Drawing.Design;
using System.Runtime.InteropServices;
using System.Windows.Forms;


namespace Marmat.Forms
{
    [StructLayout(LayoutKind.Sequential)]
    [TypeConverter(typeof(OptionsConverter))]
    [Editor("Marmat.Forms.BindingFieldUITypeEditor", typeof(UITypeEditor))]
    public partial class BindingField
    {

        public BindingField(Control control, string propertyName, IBindingSource dataSource, string dataMember, bool formattingEnabled, DataSourceUpdateMode dataSourceUpdateMode, IBindingField bindingField = null)
        {
            this._control = control;
            this.PropertyName = propertyName;
            this.DataSource = dataSource;
            this.DataMember = dataMember;
            this.FormattingEnabled = formattingEnabled;
            this.DataSourceUpdateMode = dataSourceUpdateMode;
            this.bindingField = bindingField;
        }

        private IBindingField bindingField;

        /// <summary>
        /// 获取指示绑定是否活动的值。
        /// </summary>
        /// <returns></returns>
        [Browsable(false)]
        public bool IsBinding
        {
            get => this.BaseBinding is not null && this.BaseBinding.IsBinding == true;
        }

        internal Binding BaseBinding
        {
            get => this.m_BaseBinding;
        }

        private Binding m_BaseBinding;

        /// <summary>
        /// 获取或设置一个值，该值指示是否对控件属性数据应用类型转换和格式设置。
        /// </summary>
        /// <returns>如果已针对控件属性数据启用类型转换和格式设置，则为 true；否则为 false。 默认值为 false。</returns>
        [DefaultValue(true)]
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public bool FormattingEnabled
        {
            get => this.m_formattingEnabled;
            set
            {
                this.m_formattingEnabled = value;
                if (this.BaseBinding is not null)
                    this.BaseBinding.FormattingEnabled = this.FormattingEnabled;
            }
        }
        private bool m_formattingEnabled = true;

        /// <summary>
        /// 获取绑定所属的控件
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [Browsable(false)]
        public Control Control => this._control;

        internal Control _control;

        /// <summary>
        /// 获取或设置绑定的属性名称。
        /// </summary>
        /// <returns></returns>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public string PropertyName
        {
            get => this.m_PropertyName;
            set
            {
                if (this.BaseBinding is null)
                    this.m_PropertyName = value;
            }
        }

        private string m_PropertyName;

        /// <summary>
        /// 获取或设置绑定的数据源。
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [DefaultValue(null)]
        public IBindingSource DataSource
        {
            get => (IBindingSource)this.m_DataSource;
            set
            {
                this.m_DataSource = value;
                this.Bind();
            }
        }

        private object m_DataSource;
        private string _DataMember;

        /// <summary>
        /// 获取或设置绑定的字段名
        /// </summary>
        /// <value></value>
        /// <returns></returns>
        /// <remarks></remarks>
        [DefaultValue(null)]
        [TypeConverter(typeof(StringConverter))]
        public string DataMember
        {
            get => this._DataMember;
            set
            {
                this._DataMember = value;
                this.Bind();
            }
        }

        /// <summary>
        /// System.Windows.Forms.DataSourceUpdateMode 值之一。
        /// </summary>
        [Browsable(false)]
        [DefaultValue(typeof(DataSourceUpdateMode), "OnValidation")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public DataSourceUpdateMode DataSourceUpdateMode
        {
            get => this.m_DataSourceUpdateMode;
            set => this.m_DataSourceUpdateMode = value;
        }

        private DataSourceUpdateMode m_DataSourceUpdateMode = DataSourceUpdateMode.OnValidation;

        /// <summary>
        /// 绑定。
        /// </summary>
        /// <returns></returns>
        public Binding Bind()
        {
            Binding result = null;
            if (this.DataSource is object && !string.IsNullOrEmpty(this.DataMember))
            {
                bool designMode = false;
                if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
                {
                    designMode = true;
                }
                else if (Process.GetCurrentProcess().ProcessName.ToUpper().Equals("DEVENV"))
                {
                    designMode = true;
                }

                result = Bind(this, designMode);
                this.Control.Invalidate();
            }
            else
            {
                this.Remove();
            }

            this.m_BaseBinding = result;
            return result;
        }

        /// <summary>
        /// 移除绑定
        /// </summary>
        /// <returns></returns>
        public bool Remove()
        {
            return Remove(this);
        }


        /// <summary>
        /// 绑定字段
        /// </summary>
        /// <param name="BindingField"></param>
        /// <param name="DesignMode">获取一个值，用以指示 System.ComponentModel.Component 当前是否处于设计模式。</param>
        /// <returns></returns>
        /// <remarks></remarks>
        internal static Binding Bind(BindingField BindingField, bool DesignMode)
        {
            if (DesignMode == false && BindingField is object)
            {
                Remove(BindingField);
                if (BindingField.DataSource is object && !string.IsNullOrEmpty(BindingField.DataMember) && !string.IsNullOrEmpty(BindingField.PropertyName))
                {
                    var Binding = new Binding(BindingField.PropertyName, BindingField.DataSource.GetDataSource(), BindingField.DataMember, BindingField.FormattingEnabled, BindingField.DataSourceUpdateMode);
                    BindingField.Control.DataBindings.Add(Binding);
                    if (BindingField.DataSource is IBindingFieldNotificationBus && BindingField.bindingField is IBindingFieldNotification)
                    {
                        ((IBindingFieldNotificationBus)BindingField.DataSource).Subscription(BindingField.DataMember, (IBindingFieldNotification)BindingField.bindingField);
                    }

                    return Binding;
                }
            }

            return null;
        }

        /// <summary>
        /// 移除绑定
        /// </summary>
        /// <param name="bindingField"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static bool Remove(BindingField bindingField)
        {
            bool Result = false;
            if (bindingField is object)
            {
                for (int i = 0, loopTo = bindingField.Control.DataBindings.Count - 1; i <= loopTo; i++)
                {
                    var Bind = bindingField.Control.DataBindings[i];
                    if ((Bind.PropertyName ?? "") == (bindingField.PropertyName ?? ""))
                    {
                        bindingField.Control.DataBindings.Remove(Bind);
                        Result = true;
                        if (bindingField.DataSource is IBindingFieldNotificationBus && bindingField.bindingField is IBindingFieldNotification)
                        {
                            ((IBindingFieldNotificationBus)bindingField.DataSource).Unsubscribe((IBindingFieldNotification)bindingField.bindingField);
                        }

                        break;
                    }
                }
            }

            return Result;
        }

        /// <summary>
        /// 返回表示当前对象的字符串。
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            if (this.DataSource is object || !string.IsNullOrEmpty(this.DataMember))
            {
                string dataSource = null;
                string dataMember = null;
                if (this.DataSource is object)
                {
                    if (this.DataSource is Component component)
                        dataSource = component.Site.Name;
                    else
                        dataSource = this.DataSource.ToString();
                }
                if (!string.IsNullOrEmpty(this.DataMember))
                    dataMember = this.DataMember;
                return dataSource + "." + dataMember;
            }
            return "(无)";
        }

        /// <summary>
        /// 读取控件属性的当前值并将其写入数据源。
        /// </summary>
        /// <remarks></remarks>
        public void WriteValue()
        {
            this.BaseBinding.WriteValue();
        }

        /// <summary>
        /// 将控件属性设置为从数据源读取的值。
        /// </summary>
        public void ReadValue()
        {
            this.BaseBinding.ReadValue();
        }
    }
}